//  __         ____ ___
// (_ |\/| /\ |_)|   | _  _|_ ._  _ | _  _ o _  _
// __)|  |/--\| \|   |(/_(_| || |(_)|(_)(_||(/__>
//                                       _|
// Copyright  2004 SMART Technologies Inc.
// C++ Header File ------------------------._.-._.-._.-._.-._.-._.-._.-._.---80|
//
// CSBSDK2 contains the basic functionality need by applications that need to
// recieve contact and pen tray events such as Notebook.
//
// SMART Board SDK Usage
// ------------------------._.-._.-._.-._.-._.-._.-._.-._.---|
//
// These steps are for an MFC based Windows application.
// - Add sbsdk.lib to the linker / input / additional dependencies.
// - Include "SBSDK2.h".
// - Create an instance of CSBSDK2.
// - Derive your View/Dialog/Window from CSBSDK2EventHandler.
// - In OnInitialUpdate/InitDialog/OnCreate Call CSBSDK2::SBSDKAttach with the window handle;
// - After you call SBSDKAttach or SBSDKAttachWithMsgWnd call CSBSDK2::SetEventHandler(this).
//   If you don't have to attach a window call SBSDKAttachWithMsgWnd with the first parameter
//   set to NULL to get the SDK to send you a Windows message when a SDK message needs to be
//   processed.  If you are willing to handle SDK events being called by the SDK's thread
//   you can skip calling SBSDKAttachWithMsgWnd but I advise against it.
//   If you detach your window at any point you should call SetEventHandler(NULL) first
//   for the same reason.
// - Add "ON_REGISTERED_MESSAGE(CSBSDK2::SBSDK_NEW_MESSAGE, OnSBSDKNewMessage)"
//  to the message map.
// - Add
//	LRESULT CYourClass::OnSBSDKNewMessage(WPARAM wParam, LPARAM lParam)
//	{
//		SBSDKProcessData();
//		return 0;
//	}
// - Add "afx_msg LRESULT OnSBSDKNewMessage(WPARAM wParam, LPARAM lParam);" in the .h.
// - See Platform independent instructions below.
//
//
// These steps are for a Cocoa based Mac application.
// - Add libSBSDK.a, libSocket.a and libSmartAtl.a to your project.  Each one should show up
//   under the target(s) for your application under the section "Link Binary With Libraries".
//   If you have access to the debug libraries you can add the debug versions of the above
//   libraries for use with your debug build.
// - Include "SBSDK2.h".
// - Include "SMARTWinDefs.h" in your precompiled header.
// - Define SBSDK_AS_LIBRARY in your preprocessor macros.
// - Create an instance of CSBSDK2 by using new (CSBSDK2 *m_pSBSDK = new CSBSDK2;).
// To recieve events from SBSDK follow these steps.  See the MacSBSDKSampleApp for an example.
// - Make a copy of SBSDK2EventProtocol.h from the MacSBSDKSampleApp and import it.
// - Derive a Cocoa class (likely your apps main window) from SBSDK2EventProtocol.
// - To avoid multithreading issues create a NSPort and add it to your run loop.  Create a port
//   message handler and in it call m_pSBSDK2->SBSDKProcessData().
// - Override OnMessageReceived and send a message through the NSPort created earlier.
// - Create an instance of CSBSDK2EventHandlerImpl using new.  It can be found in the sample
//   app MacSBSDKSampleApp.  This class bridges the gap between c++ and objective c.
// - Call pSBSDK2EventHandlerImpl->SetEventHandler(self) and m_pSBSDK2->SetEventHandler(pSBSDK2EventHandlerImpl).
// - Call m_pSBSDK2->SBSDKAttach to register a window with the SMART Board service.  When the window
//   moves you will also have to call SBSDKWindowMoved and when you loose or get focues you need to call
//   SBSDKWindowHasFocus.  One place to handle this is in a window delegate.
// - See Platform independent instructions below.
//
//
// Steps for a QT 4 based Linux application.
// - Link your project with libSBSDK.a, libSocket.a and libSmartAtl.a.
// - Include "SBSDK2.h"
// - Include "SMARTWinDefs.h" in your precompiled header.
// - Define SBSDK_AS_LIBRARY in your preprocessor macros.
// - Create an instance of CSBSDK2.
// - Derive your Window from CSBSDK2EventHandler.
// - In your window create a slot and in that slot call CSBSDK2::SBSDKProcessData;
// - In your window create a signal, connect this signal to the slot created earlier.
// - Call CSBSDK2::SetEventHandler(this) in your windows constructor.
// - In QWidget::showEvent call CSBSDK2::SBSDKAttach with the window id;
// - Override OnMessageReceived and send a message through the signal created earlier.
// - See Platform independent instructions below.
//
//
// Platform independent instructions.
// - Override OnXYDown, OnXYMove, and OnXYUp for projected events.
// - Override OnXYNonProjectedDown, OnXYNonProjectedMove, and OnXYNonProjectedUp
//   for non-projected events.
// - For each one, there is an iPointerID.  Use this ID to handle multiple boards
//   and multiple pointers on a board (in the case of DViT).  With the ID, retrieve
//   tool attributes for that pointer with the functions provided like SBSDKGetToolColor.
//   Also use the ID to separate the events coming from different boards so that they
//   don't conflict with each other.  This allows two people to write at the same time.
//   In non-projected mode, if there is more than one board (SBSDKGetConnectedBoardCount),
//   you may want to have each board write on a different page.  Use
//   GetBoardNumberFromPointerID to determine which page to associate with.
// - Override the tool events for visual feedback if desired when handling multiple
//   boards.  If not handling multiple boards, use the tool events to set your "global"
//   tool attributes.
// - Override the button events.  If SBSDKIsBoardProjected, only do the button action
//  if your window/application has focus.  Otherwise, always perform the button action
//  for non-projected mode.

#pragma once

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the SBSDK_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// SBSDK_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.

// includes
# ifdef _LINUX
#include <X11/Xlib.h>
#include "AtlTypes.h"
#endif

// defines
#ifdef SBSDK_EXPORTS
#define SBSDK_API __declspec(dllexport)
#elif SBSDK_AS_LIBRARY
#define SBSDK_API
#else
#define SBSDK_API __declspec(dllimport)
#endif

#define SBSDK_REG_ID 1
#define SBSDK2_REG_ID 2

enum SBSDK_TOOL_TYPE
{
	SB_NO_TOOL = 0,
	SB_PEN,
	SB_ERASER,
	SB_RECTANGLE,
	SB_LINE,
	SB_CIRCLE,
	SB_POLYGON,
	SB_STAMP
};

enum SBSDK_MOUSE_EVENT_FLAG
{
	SB_MEF_DEFAULT = 0,
	SB_MEF_ALWAYS,
	SB_MEF_NEVER
};

#define SBSDK_NON_PROJECTED_RANGE 4096

class CSBSDKWnd
{
public:
	// Windows and Mac
	SBSDK_API CSBSDKWnd();
	SBSDK_API ~CSBSDKWnd();

	SBSDK_API int operator==(CSBSDKWnd &Wnd);
	SBSDK_API int operator!=(CSBSDKWnd &Wnd);
	SBSDK_API void Empty();
	SBSDK_API bool IsEmpty();
	SBSDK_API bool ScreenToClient(int &x, int &y);
	SBSDK_API bool ClientToScreen(int &x, int &y);

#ifdef WIN32

public:
	// Windows specific
	SBSDK_API CSBSDKWnd(HWND hWnd);
	SBSDK_API void SetWindow(HWND hWnd);
	SBSDK_API HWND GetWindow();
	SBSDK_API bool GetWindowRect(RECT &rect);

private:
	HWND m_hWnd;

#elif defined _MAC

public:
	// Mac specific 
	SBSDK_API CSBSDKWnd(float bottom, float left, float width, float height);
	SBSDK_API void GetWindowRect(float &bottom, float &left, float &width, float &height);
	SBSDK_API void SetWindowRect(float bottom, float left, float width, float height);
	SBSDK_API int GetId();
	SBSDK_API void SetId(int id);
	SBSDK_API int GetAppId();
	SBSDK_API void SetAppId(int id);

private:

	float m_fBottom, m_fLeft, m_fWidth, m_fHeight;
	int m_id;	// the SDK will assign an id to allow the client
				// to reference the same window in the future
	int m_iAppId;  // Used only by the service.

#elif defined _LINUX

public:
	// Linux specific
	SBSDK_API CSBSDKWnd(Window window);
	SBSDK_API void SetWindow(Window window);
	SBSDK_API Window GetWindow();
	SBSDK_API bool GetWindowRect(RECT &rect);

private:
	Window m_window;

#endif

};

class CSBSDKInternal;

#if defined(UNICODE) || defined(_UNICODE)

#define SBSDK_CHAR wchar_t
#define OnXMLAnnot OnXMLAnnotW
#define OnXMLToolChange OnXMLToolChangeW
#define SBSDKGetXMLTool SBSDKGetXMLToolW

#else  // defined(UNICODE) || defined(_UNICODE)

#define SBSDK_CHAR char
#define OnXMLAnnot OnXMLAnnotA
#define OnXMLToolChange OnXMLToolChangeA
#define SBSDKGetXMLTool SBSDKGetXMLToolA

#endif  // defined(UNICODE) || defined(_UNICODE)

class CSBSDK2EventHandler
{
public:
	SBSDK_API virtual ~CSBSDK2EventHandler() {};

	// Parameter names are commented out to stop unused parameter warnings on Mac.
	// When you implement one of these uncomment the parameter names in your code.

	// Projected (X,Y) events.
	SBSDK_API virtual void OnXYDown(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};
	SBSDK_API virtual void OnXYMove(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};
	SBSDK_API virtual void OnXYUp(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};
	SBSDK_API virtual void OnXYHover(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};

	// Non-projected (X,Y) events.
	SBSDK_API virtual void OnXYNonProjectedDown(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};
	SBSDK_API virtual void OnXYNonProjectedMove(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};
	SBSDK_API virtual void OnXYNonProjectedUp(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};
	SBSDK_API virtual void OnXYNonProjectedHover(int /*x*/, int /*y*/, int /*z*/, int /*iPointerID*/){};

	// To recieve these events call CSBSDK2::SBSDKAttach with bSendXMLAnnotations
	// set to true.
	// You can implement OnXMLAnnot(SBSDK_CHAR * /*szXMLAnnot*/), not the W or A version.
	SBSDK_API virtual void OnXMLAnnotW(wchar_t * /*szXMLAnnot*/){};
	SBSDK_API virtual void OnXMLAnnotA(char * /*szXMLAnnot*/){};

	// Tool events.  These will not be fired if you request to recieve XML tool changes.
	SBSDK_API virtual void OnNoTool(int /*iPointerID*/){};
	SBSDK_API virtual void OnPen(int /*iPointerID*/){};
	SBSDK_API virtual void OnEraser(int /*iPointerID*/){};
	SBSDK_API virtual void OnRectangle(int /*iPointerID*/){};
	SBSDK_API virtual void OnLine(int /*iPointerID*/){};
	SBSDK_API virtual void OnCircle(int /*iPointerID*/){};
	SBSDK_API virtual void OnStamp(int /*iPointerID*/){};

	// To recieve these events call CSBSDK2::SBSDKSendXMLToolChanges with the value true.
	// You  implement OnXMLToolChange(int iBoardID, SBSDK_CHAR */*szXMLTool*/), not the W or A version.
	// You can get the XML for the tool at a later time by calling CSBSDK2::SBSDKGetXMLTool
	SBSDK_API virtual void OnXMLToolChangeW(int /*iBoardID*/, wchar_t * /*szXMLTool*/){};
	SBSDK_API virtual void OnXMLToolChangeA(int /*iBoardID*/, char * /*szXMLTool*/){};

	// OnPrint, OnNext, OnPrevious and OnClear have been depreciated
	// as of Jan. 10, 2006.  Use OnPenTrayButton in CSBSDK2AdvancedEventhandler instead.
	// Button events.
	SBSDK_API virtual void OnPrint(int /*iPointerID*/){};
	SBSDK_API virtual void OnNext(int /*iPointerID*/){};
	SBSDK_API virtual void OnPrevious(int /*iPointerID*/){};
	SBSDK_API virtual void OnClear(int /*iPointerID*/){};

	// Information
	SBSDK_API virtual void OnSBSDKBoardStatusChange(){};

#ifndef WIN32
	SBSDK_API virtual bool OnMessageReceived() { return false; };
#endif
};

class CSBSDK2
{
public:
	// By default multiple instances of CSBSDK2 will use the
	// same connection to the service.  If you want each instance
	// to have seperate connections (allows you to have seperate
	// event handlers) then pass in true to the constructor.
	SBSDK_API CSBSDK2(bool bSeperateConnection = false);
	SBSDK_API virtual ~CSBSDK2(void);

	SBSDK_API void SetEventHandler(CSBSDK2EventHandler *pHandler);

	// Connect your window.
	SBSDK_API void SBSDKAttach(CSBSDKWnd &Wnd, bool bSendXMLAnnotations = false);
#ifdef WIN32
	// The window handle that is given to the first call of SBSDKAttach
	// is where CSBSDK::SBSDK_NEW_MESSAGE messages are sent.  If you
	// prefer to have the messages sent to another window call this.
	SBSDK_API void SBSDKAttachWithMsgWnd(CSBSDKWnd &Wnd, bool bSendXMLAnnotations, CSBSDKWnd WndProcessData);
#endif

	SBSDK_API void SBSDKDetachWnd(CSBSDKWnd &Wnd);

#ifdef _MAC
	// The Wnd parameter in these three calls must be a window previously
	// attached with a call to SBSDKAttach or SBSDKAttachWithMsgWnd.
	SBSDK_API void SBSDKWindowMoved(CSBSDKWnd &AttachedWnd);
	SBSDK_API void SBSDKWindowHasFocus(CSBSDKWnd &AttachedWnd, bool bFocus);
	SBSDK_API void SBSDKWindowLevel(CSBSDKWnd &AttachedWnd, int iLevel);
#endif

	SBSDK_API CSBSDKWnd SBSDKGetXYDestinationWnd();

	// Handle this message and call SBSDKProcessData.
	SBSDK_API static UINT SBSDK_NEW_MESSAGE;
	SBSDK_API void SBSDKProcessData();

	// Tool Attributes.  These will not work if you request to recieve
	// XML tool changes.
	SBSDK_API SBSDK_TOOL_TYPE SBSDKGetToolType(int iPointerID);
	SBSDK_API COLORREF SBSDKGetToolColor(int iPointerID);
	SBSDK_API float SBSDKGetToolOpacity(int iPointerID);
	SBSDK_API COLORREF SBSDKGetToolFillColor(int iPointerID);
	SBSDK_API float SBSDKGetToolFillOpacity(int iPointerID);
	SBSDK_API int SBSDKGetToolWidth(int iPointerID);

	// If you want to recieve XML tool changes call before you attach any windows.
	SBSDK_API void SBSDKSendXMLToolChanges(bool bSendXMLToolChanges);
	// These two calls return a temporary pointer.  If you want to keep the XML around
	// make a copy of it.
	SBSDK_API wchar_t* SBSDKGetXMLToolW(int iPointerID);
	SBSDK_API char* SBSDKGetXMLToolA(int iPointerID);

	// Mouse events, to apply this setting to all pointer ID's use -1 for the pointer ID
	SBSDK_API void SBSDKSendMouseEvents(CSBSDKWnd &AttachedWnd, SBSDK_MOUSE_EVENT_FLAG iFlag, int iPointerID);

	// Information

	// SBSDKIsABoardConnected returns true if 1 or more boards are connected
	// and working properly.
	SBSDK_API bool SBSDKIsABoardConnected();
	// SBSDKGetConnectedBoardCount returns the number of connected boards
	// that are working properly.
	SBSDK_API int SBSDKGetConnectedBoardCount();
	// SBSDKGetBoardCount returns the number of board the service has records of.
	// Each one may or may not be connected or working properly.
	SBSDK_API int SBSDKGetBoardCount();
	SBSDK_API bool SBSDKIsBoardProjected(int iPointerID);
	SBSDK_API int SBSDKGetBoardNumberFromPointerID(int iPointerID);
	SBSDK_API bool SBSDKGetSoftwareVersion(int * piMajor, int * piMinor, int * piUpdate, int * piBuild);
	// SBSDKGetCurrentBoard Returns the current boards ID.  The current board is
	// the last board the user touched.
	SBSDK_API int SBSDKGetCurrentBoard();
	// A regular on tool change event will come after calling SBSDKGetCurrentTool.
	SBSDK_API void SBSDKGetCurrentTool();

	SBSDK_API CSBSDKInternal* GetSBSDKInternal();

private:
	CSBSDKInternal *m_pSBSDKInternal;
	bool m_bSeperateConnection;
};
